#include "More3D.h"
#include <vector>
#include "AutoRotateCameraShader.h"
#include "MovingCameraByKeybord.h"
#include "Renderer.h"
#include "RotationByTimeShader.h"
#include "TextureProxyShader.h"
More3D::More3D(GLFWwindow* window) : window(window)
{
    /**
     以5个单元为一组，前三个是顶点坐标，后两个是纹理坐标
    */
    vertices = {
        // vertices                     // texture coords
        -0.5f, -0.5f, -0.5f, 0.0f, 0.0f, //
        0.5f,  -0.5f, -0.5f, 1.0f, 0.0f, //
        0.5f,  0.5f,  -0.5f, 1.0f, 1.0f, 0.5f,  0.5f,  -0.5f, 1.0f, 1.0f,
        -0.5f, 0.5f,  -0.5f, 0.0f, 1.0f, -0.5f, -0.5f, -0.5f, 0.0f, 0.0f,

        -0.5f, -0.5f, 0.5f,  0.0f, 0.0f, 0.5f,  -0.5f, 0.5f,  1.0f, 0.0f,
        0.5f,  0.5f,  0.5f,  1.0f, 1.0f, 0.5f,  0.5f,  0.5f,  1.0f, 1.0f,
        -0.5f, 0.5f,  0.5f,  0.0f, 1.0f, -0.5f, -0.5f, 0.5f,  0.0f, 0.0f,

        -0.5f, 0.5f,  0.5f,  1.0f, 0.0f, -0.5f, 0.5f,  -0.5f, 1.0f, 1.0f,
        -0.5f, -0.5f, -0.5f, 0.0f, 1.0f, -0.5f, -0.5f, -0.5f, 0.0f, 1.0f,
        -0.5f, -0.5f, 0.5f,  0.0f, 0.0f, -0.5f, 0.5f,  0.5f,  1.0f, 0.0f,

        0.5f,  0.5f,  0.5f,  1.0f, 0.0f, 0.5f,  0.5f,  -0.5f, 1.0f, 1.0f,
        0.5f,  -0.5f, -0.5f, 0.0f, 1.0f, 0.5f,  -0.5f, -0.5f, 0.0f, 1.0f,
        0.5f,  -0.5f, 0.5f,  0.0f, 0.0f, 0.5f,  0.5f,  0.5f,  1.0f, 0.0f,

        -0.5f, -0.5f, -0.5f, 0.0f, 1.0f, 0.5f,  -0.5f, -0.5f, 1.0f, 1.0f,
        0.5f,  -0.5f, 0.5f,  1.0f, 0.0f, 0.5f,  -0.5f, 0.5f,  1.0f, 0.0f,
        -0.5f, -0.5f, 0.5f,  0.0f, 0.0f, -0.5f, -0.5f, -0.5f, 0.0f, 1.0f,

        -0.5f, 0.5f,  -0.5f, 0.0f, 1.0f, 0.5f,  0.5f,  -0.5f, 1.0f, 1.0f,
        0.5f,  0.5f,  0.5f,  1.0f, 0.0f, 0.5f,  0.5f,  0.5f,  1.0f, 0.0f,
        -0.5f, 0.5f,  0.5f,  0.0f, 0.0f, -0.5f, 0.5f,  -0.5f, 0.0f, 1.0f};
    vector<int> empty;
    target = new TextureProxyShader(
        vertices, empty,
        [&window](const string& vectexSrc, const string& fragmentSrc)
        {
            // 物体自旋
            // return new RotationByTimeShader(vectexSrc, fragmentSrc);
            //  相机沿y轴旋转
            // return new AutoRotateCameraShader(vectexSrc, fragmentSrc);

            // 可以手动控制相机移动
            return new MovingCameraByKeybord(vectexSrc, fragmentSrc,window);
        });

    cubePositions = {
        glm::vec3(0.0f, 0.0f, 0.0f),    glm::vec3(2.0f, 5.0f, -15.0f),
        glm::vec3(-1.5f, -2.2f, -2.5f), glm::vec3(-3.8f, -2.0f, -12.3f),
        glm::vec3(2.4f, -0.4f, -3.5f),  glm::vec3(-1.7f, 3.0f, -7.5f),
        glm::vec3(1.3f, -2.0f, -2.5f),  glm::vec3(1.5f, 2.0f, -2.5f),
        glm::vec3(1.5f, 0.2f, -1.5f),   glm::vec3(-1.3f, 1.0f, -1.5f)};
}
/**
 *  This happens because when OpenGL draws your cube triangle-by-triangle,
 *  fragment by fragment, it will overwrite any pixel color that may have
 * already been drawn there before. Since OpenGL gives no guarantee on the order
 * of triangles rendered (within the same draw call), some triangles are drawn
 * on top of each other even though one should clearly be in front of the other.
 *
 *  Luckily, OpenGL stores depth information in a buffer called the z-buffer
 * that allows OpenGL to decide when to draw over a pixel and when not to. Using
 * the z-buffer we can configure OpenGL to do depth-testing.
 */
unsigned int More3D::createShaderProgram()
{
    /**
     *However, if we want to make sure OpenGL actually performs the depth
     *testing we first need to tell OpenGL we want to enable depth testing; it
     *is disabled by default. We can enable depth testing using glEnable. The
     *glEnable and glDisable functions allow us to enable/disable certain
     *functionality in OpenGL. That functionality is then enabled/disabled until
     *another call is made to disable/enable it. Right now we want to enable
     *depth testing by enabling GL_DEPTH_TEST:
     */
    glEnable(GL_DEPTH_TEST);

    return target->createShaderProgram();
}

void More3D::prepareVAO() { return target->prepareVAO(); }
void More3D::update()
{
    /* 因为颜色之前已经被清除了（在main()的循环中），所以这里只清除深度信息即可
    Since we're using a depth buffer we also want to clear the depth buffer
    before each render iteration (otherwise the depth information of the
    previous frame stays in the buffer). Just like clearing the color buffer, we
    can clear the depth buffer by specifying the DEPTH_BUFFER_BIT bit in the
    glClear function:
    */
    glClear(/*GL_COLOR_BUFFER_BIT |*/ GL_DEPTH_BUFFER_BIT);

    // 基于友元，获得其私有属性
    ShaderProgram* someShader = target->target;

    if (MovingLocationShader* movingLocationShader =
            dynamic_cast<MovingLocationShader*>(someShader))
    {

        for (const auto& position : cubePositions)
        {
            movingLocationShader->setTransactionVector(position);
            target->update();

            glDrawArrays(GL_TRIANGLES, 0, 36);
        }
    }
}
void More3D::render() {}

More3D::~More3D() { delete target; }